home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / lib / emacs / 19.22 / i386-sco3.2v4 / rcs2log < prev    next >
Text File  |  1994-07-06  |  12KB  |  434 lines

  1. #!/bin/sh
  2.  
  3. # RCS to ChangeLog generator
  4.  
  5. # Generate a change log prefix from RCS files and the ChangeLog (if any).
  6. # Output the new prefix to standard output.
  7. # You can edit this prefix by hand, and then prepend it to ChangeLog.
  8.  
  9. # Ignore log entries that start with `#'.
  10. # Clump together log entries that start with `{topic} ',
  11. # where `topic' contains neither white space nor `}'.
  12.  
  13. # Author: Paul Eggert <eggert@twinsun.com>
  14.  
  15. # $Id: rcs2log,v 1.16 1993/10/19 02:50:31 eggert Exp $
  16.  
  17. # Copyright 1992, 1993 Free Software Foundation, Inc.
  18.  
  19. # This program is free software; you can redistribute it and/or modify
  20. # it under the terms of the GNU General Public License as published by
  21. # the Free Software Foundation; either version 2, or (at your option)
  22. # any later version.
  23. # This program is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26. # GNU General Public License for more details.
  27. # You should have received a copy of the GNU General Public License
  28. # along with this program; see the file COPYING.  If not, write to
  29. # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  30.  
  31. nl='
  32. '
  33.  
  34. # Parse options.
  35.  
  36. # defaults
  37. : ${TMPDIR=/tmp}
  38. hostname= # name of local host (if empty, will deduce it later)
  39. indent=8 # indent of log line
  40. initialize_fullname= # awk assignments to set up fullname array
  41. initialize_mailaddr= # awk assignments to set up mailaddr array
  42. length=79 # suggested max width of log line
  43. logins= # login names for people we know fullnames and mailaddresses of
  44. loginsout= # temporary file holding sorted logins
  45. rlog_options= # options to pass to rlog
  46. tabwidth=8 # width of horizontal tab
  47.  
  48. while :
  49. do
  50.     case $1 in
  51.     -i)    indent=${2?};;
  52.     -h)    hostname=${2?};;
  53.     -l)    length=${2?};;
  54.     -n)    logins=$logins$nl${2?}
  55.         loginsout=$TMPDIR/rcs2log$$l
  56.         case $2${3?}${4?} in
  57.         *\"* | *\\* | *"$nl"*)
  58.             echo >&2 "$0: -n '$2' '$3' '$4': special characters not allowed"
  59.             exit 1
  60.         esac
  61.         initialize_fullname="$initialize_fullname
  62.             fullname[\"$2\"] = \"$3\""
  63.         initialize_mailaddr="$initialize_mailaddr
  64.             mailaddr[\"$2\"] = \"$4\""
  65.         shift; shift;;
  66.     -r)    rlog_options=$rlog_options$nl${2?};;
  67.     -t)    tabwidth=${2?};;
  68.     -*)    echo >&2 "$0: usage: $0 [options] [file ...]
  69. Options:
  70.     [-h hostname] [-i indent] [-l length] [-n login fullname mailaddr]...
  71.     [-r rlog_option]... [-t tabwidth]"
  72.         exit 1;;
  73.     *)    break
  74.     esac
  75.     shift; shift
  76. done
  77.  
  78. month_data='
  79.     m[0]="Jan"; m[1]="Feb"; m[2]="Mar"
  80.     m[3]="Apr"; m[4]="May"; m[5]="Jun"
  81.     m[6]="Jul"; m[7]="Aug"; m[8]="Sep"
  82.     m[9]="Oct"; m[10]="Nov"; m[11]="Dec"
  83.  
  84.     # days in non-leap year thus far, indexed by month (0-12)
  85.     mo[0]=0; mo[1]=31; mo[2]=59; mo[3]=90
  86.     mo[4]=120; mo[5]=151; mo[6]=181; mo[7]=212
  87.     mo[8]=243; mo[9]=273; mo[10]=304; mo[11]=334
  88.     mo[12]=365
  89. '
  90.  
  91.  
  92. # Log into $rlogout the revisions checked in since the first ChangeLog entry.
  93.  
  94. date=1970
  95. if test -s ChangeLog
  96. then
  97.     # Add 1 to seconds to avoid duplicating most recent log.
  98.     e='
  99.         /^... ... [ 0-9][0-9] [ 0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9]+ /{
  100.             '"$month_data"'
  101.             year = $5
  102.             for (i=0; i<=11; i++) if (m[i] == $2) break
  103.             dd = $3
  104.             hh = substr($0,12,2)
  105.             mm = substr($0,15,2)
  106.             ss = substr($0,18,2)
  107.             ss++
  108.             if (ss == 60) {
  109.                 ss = 0
  110.                 mm++
  111.                 if (mm == 60) {
  112.                     mm = 0
  113.                     hh++
  114.                     if (hh == 24) {
  115.                         hh = 0
  116.                         dd++
  117.                         monthdays = mo[i+1] - mo[i]
  118.                         if (i == 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0)) monthdays++
  119.                         if (dd == monthdays + 1) {
  120.                             dd = 1
  121.                             i++
  122.                             if (i == 12) {
  123.                                 i = 0
  124.                                 year++
  125.                             }
  126.                         }
  127.                     }
  128.                 }
  129.             }
  130.             printf "%d/%02d/%02d %02d:%02d:%02d\n", year, i+1, dd, hh, mm, ss
  131.             exit
  132.         }
  133.     '
  134.     d=`awk "$e" <ChangeLog` || exit
  135.     case $d in
  136.     ?*) date=$d
  137.     esac
  138. fi
  139. datearg="-d>$date"
  140.  
  141. # With no arguments, examine all files under the RCS directory.
  142. case $# in
  143. 0)
  144.     files=
  145.     for file in RCS/.* RCS/* .*,v *,v
  146.     do
  147.         case $file in
  148.         RCS/. | RCS/..) continue;;
  149.         RCS/.\* | RCS/\* | .\*,v | \*,v) test -f "$file" || continue
  150.         esac
  151.         files=$files$nl$file
  152.     done
  153.     case $files in
  154.     '') exit 0
  155.     esac
  156.     oldIFS=$IFS
  157.     IFS=$nl
  158.     set $files
  159.     IFS=$oldIFS
  160. esac
  161.  
  162. rlogout=$TMPDIR/rcs2log$$r
  163. trap exit 1 2 13 15
  164. trap "rm -f $loginsout $rlogout; exit 1" 0
  165.  
  166. rlog "$datearg" $rlog_options "$@" >$rlogout || exit
  167.  
  168.  
  169. # Get the full name of each author the logs mention, and set initialize_fullname
  170. # to awk code that initializes the `fullname' awk associative array.
  171. # Warning: foreign authors (i.e. not known in the passwd file) are mishandled;
  172. # you have to fix the resulting output by hand.
  173.  
  174. case $loginsout in
  175. ?*) sort -u -o $loginsout <<EOF || exit
  176. $logins
  177. EOF
  178. esac
  179. authors=`
  180.     sed -n 's|^date: *[0-9]*/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]; *author: *\([^; ]*\).*|\1|p' <$rlogout |
  181.     case $loginsout in
  182.     '') sort -u;;
  183.     ?*) sort -u | comm -23 - $loginsout
  184.     esac
  185. `
  186. case $authors in
  187. ?*)
  188.     initialize_author=
  189.     for author in $authors
  190.     do
  191.         initialize_author="$initialize_author
  192.             author[\"$author\"] = 1
  193.         "
  194.     done
  195.     awkscript='
  196.         BEGIN {
  197.             alphabet = "abcdefghijklmnopqrstuvwxyz"
  198.             ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  199.             '"$initialize_author"'
  200.         }
  201.         {
  202.             if (author[$1]) {
  203.                 fullname = $5
  204.                 if (fullname ~ /[0-9]+-[^(]*\([0-9]+\)$/) {
  205.                     # Remove the junk from fullnames like "0000-Admin(0000)".
  206.                     fullname = substr(fullname, index(fullname, "-") + 1)
  207.                     fullname = substr(fullname, 1, index(fullname, "(") - 1)
  208.                 }
  209.                 if (fullname ~ /,[^ ]/) {
  210.                     # Some sites put comma-separated junk after the fullname.
  211.                     # Remove it, but leave "Bill Gates, Jr" alone.
  212.                     fullname = substr(fullname, 1, index(fullname, ",") - 1)
  213.                 }
  214.                 abbr = index(fullname, "&")
  215.                 if (abbr) {
  216.                     a = substr($1, 1, 1)
  217.                     A = a
  218.                     i = index(alphabet, a)
  219.                     if (i) A = substr(ALPHABET, i, 1)
  220.                     fullname = substr(fullname, 1, abbr-1) A substr($1, 2) substr(fullname, abbr+1)
  221.                 }
  222.                 printf "fullname[\"%s\"] = \"%s\"\n", $1, fullname
  223.                 author[$1] = 0
  224.             }
  225.         }
  226.     '
  227.  
  228.     initialize_fullname=`
  229.         (cat /etc/passwd; ypmatch $authors passwd) 2>/dev/null |
  230.         awk -F: "$awkscript"
  231.     `$initialize_fullname
  232. esac
  233.  
  234.  
  235. # Function to print a single log line.
  236. # We don't use awk functions, to stay compatible with old awk versions.
  237. # `Log' is the log message (with \n replaced by \r).
  238. # `files' contains the affected files.
  239. printlogline='{
  240.  
  241.     # Following the GNU coding standards, rewrite
  242.     #    * file: (function): comment
  243.     # to
  244.     #    * file (function): comment
  245.     if (Log ~ /^\([^)]*\): /) {
  246.         i = index(Log, ")")
  247.         files = files " " substr(Log, 1, i)
  248.         Log = substr(Log, i+3)
  249.     }
  250.  
  251.     # If "label: comment" is too long, break the line after the ":".
  252.     sep = " "
  253.     if ('"$length"' <= '"$indent"' + 1 + length(files) + index(Log, CR)) sep = "\n" indent_string
  254.  
  255.     # Print the label.
  256.     printf "%s*%s:", indent_string, files
  257.  
  258.     # Print each line of the log, transliterating \r to \n.
  259.     while ((i = index(Log, CR)) != 0) {
  260.         logline = substr(Log, 1, i-1)
  261.         if (logline ~ /[^     ]/) {
  262.             printf "%s%s\n", sep, logline
  263.         } else {
  264.             print ""
  265.         }
  266.         sep = indent_string
  267.         Log = substr(Log, i+1)
  268.     }
  269. }'
  270.  
  271. case $hostname in
  272. '')
  273.     hostname=`(
  274.         hostname || uname -n || uuname -l || cat /etc/whoami
  275.     ) 2>/dev/null` || {
  276.         echo >&2 "$0: cannot deduce hostname"
  277.         exit 1
  278.     }
  279. esac
  280.  
  281.  
  282. # Process the rlog output, generating ChangeLog style entries.
  283.  
  284. # First, reformat the rlog output so that each line contains one log entry.
  285. # Transliterate \n to \r so that multiline entries fit on a single line.
  286. # Discard irrelevant rlog output.
  287. awk <$rlogout '
  288.     /^Working file:/ { filename = $3 }
  289.     /^date: /, /^(-----------*|===========*)$/ {
  290.         if ($0 ~ /^branches: /) { next }
  291.         if ($0 ~ /^date: [0-9][ \/0-9:]*;/) {
  292.             time = substr($3, 1, length($3)-1)
  293.             author = substr($5, 1, length($5)-1)
  294.             printf "%s %s %s %s %c", filename, $2, time, author, 13
  295.             next
  296.         }
  297.         if ($0 ~ /^(-----------*|===========*)$/) { print ""; next }
  298.         printf "%s%c", $0, 13
  299.     }
  300. ' |
  301.  
  302. # Now each line is of the form
  303. # FILENAME YYYY/MM/DD HH:MM:SS AUTHOR \rLOG
  304. #    where \r stands for a carriage return,
  305. #    and each line of the log is terminated by \r instead of \n.
  306. # Sort the log entries, first by date+time (in reverse order),
  307. # then by author, then by log entry, and finally by file name (just in case).
  308. sort +1 -3r +3 +0 |
  309.  
  310. # Finally, reformat the sorted log entries.
  311. awk '
  312.     BEGIN {
  313.         # Some awks do not understand "\r" or "\013", so we have to
  314.         # put a carriage return directly in the file.
  315.         CR="" # <-- There is a single CR between the " chars here.
  316.  
  317.         # Initialize the fullname and mailaddr associative arrays.
  318.         '"$initialize_fullname"'
  319.         '"$initialize_mailaddr"'
  320.  
  321.         # Initialize indent string.
  322.         indent_string = ""
  323.         i = '"$indent"'
  324.         if (0 < '"$tabwidth"')
  325.             for (;  '"$tabwidth"' <= i;  i -= '"$tabwidth"')
  326.                 indent_string = indent_string "\t"
  327.         while (1 <= i--)
  328.             indent_string = indent_string " "
  329.  
  330.         # Set up date conversion tables.
  331.         # RCS uses a nice, clean, sortable format,
  332.         # but ChangeLog wants the traditional, ugly ctime format.
  333.  
  334.         # January 1, 0 AD (Gregorian) was Saturday = 6
  335.         EPOCH_WEEKDAY = 6
  336.         # Of course, there was no 0 AD, but the algorithm works anyway.
  337.  
  338.         w[0]="Sun"; w[1]="Mon"; w[2]="Tue"; w[3]="Wed"
  339.         w[4]="Thu"; w[5]="Fri"; w[6]="Sat"
  340.  
  341.         '"$month_data"'
  342.     }
  343.  
  344.     {
  345.         newlog = substr($0, 1 + index($0, CR))
  346.  
  347.         # Ignore log entries prefixed by "#".
  348.         if (newlog ~ /^#/) { next }
  349.  
  350.         if (Log != newlog || date != $2 || author != $4) {
  351.  
  352.             # The previous log and this log differ.
  353.  
  354.             # Print the old log.
  355.             if (date != "") '"$printlogline"'
  356.  
  357.             # Logs that begin with "{clumpname} " should be grouped together,
  358.             # and the clumpname should be removed.
  359.             # Extract the new clumpname from the log header,
  360.             # and use it to decide whether to output a blank line.
  361.             newclumpname = ""
  362.             sep = "\n"
  363.             if (date == "") sep = ""
  364.             if (newlog ~ /^\{[^     }]*}[     ]/) {
  365.                 i = index(newlog, "}")
  366.                 newclumpname = substr(newlog, 1, i)
  367.                 while (substr(newlog, i+1) ~ /^[     ]/) i++
  368.                 newlog = substr(newlog, i+1)
  369.                 if (clumpname == newclumpname) sep = ""
  370.             }
  371.             printf sep
  372.             clumpname = newclumpname
  373.  
  374.             # Get ready for the next log.
  375.             Log = newlog
  376.             if (files != "")
  377.                 for (i in filesknown)
  378.                     filesknown[i] = 0
  379.             files = ""
  380.         }
  381.         if (date != $2  ||  author != $4) {
  382.             # The previous date+author and this date+author differ.
  383.             # Print the new one.
  384.             date = $2
  385.             author = $4
  386.  
  387.             # Convert nice RCS date like "1992/01/03 00:03:44"
  388.             # into ugly ctime date like "Fri Jan  3 00:03:44 1992".
  389.             # Calculate day of week from Gregorian calendar.
  390.             i = index($2, "/")
  391.             year = substr($2, 1, i-1) + 0
  392.             monthday = substr($2, i+1)
  393.             i = index(monthday, "/")
  394.             month = substr(monthday, 1, i-1) + 0
  395.             day = substr(monthday, i+1) + 0
  396.             leap = 0
  397.             if (2 < month && year%4 == 0 && (year%100 != 0 || year%400 == 0)) leap = 1
  398.             days_since_Sunday_before_epoch = EPOCH_WEEKDAY + year * 365 + int((year + 3) / 4) - int((year + 99) / 100) + int((year + 399) / 400) + mo[month-1] + leap + day - 1
  399.  
  400.             # Print "date  fullname  (email address)".
  401.             # Get fullname and email address from associative arrays;
  402.             # default to author and author@hostname if not in arrays.
  403.             if (fullname[author])
  404.                 auth = fullname[author]
  405.             else
  406.                 auth = author
  407.             printf "%s %s %2d %s %d  %s  ", w[days_since_Sunday_before_epoch%7], m[month-1], day, $3, year, auth
  408.             if (mailaddr[author])
  409.                 printf "(%s)\n\n", mailaddr[author]
  410.             else
  411.                 printf "(%s@%s)\n\n", author, "'"$hostname"'"
  412.         }
  413.         if (! filesknown[$1]) {
  414.             filesknown[$1] = 1
  415.             if (files == "") files = " " $1
  416.             else files = files ", " $1
  417.         }
  418.     }
  419.     END {
  420.         # Print the last log.
  421.         if (date != "") {
  422.             '"$printlogline"'
  423.             printf "\n"
  424.         }
  425.     }
  426. ' &&
  427.  
  428.  
  429. # Exit successfully.
  430.  
  431. exec rm -f $loginsout $rlogout
  432.